package com.prj.ufdm.web.security;

import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import com.prj.ufdm.web.bpo.SysFunctionBPO;
import com.prj.ufdm.web.bpo.SysUserBPO;
import com.prj.ufdm.web.bpo._impl.SysFunctionBPOImpl;
import com.prj.ufdm.web.bpo._impl.SysUserBPOImpl;
import com.prj.ufdm.web.enums.WebRetCodeEnum;
import com.prj.ufdm.web.model.SysUser;
import com.prj.ufdm.web.security.branch.TokenAuthenticationFailure;
import com.prj.ufdm.web.security.branch.TokenAuthenticationSuccess;
import com.prj.ufdm.core.util.UfdmDateUtil;

/**  
 * Token 验证过滤器 
 * @author 胡义振  
 * @date 2018年3月22日  
*/
public class TokenAuthentication  extends AbstractAuthenticationProcessingFilter {

	private SysUserBPO sysUserBPO;
	private SysFunctionBPO sysFunctionBPO;
	
	public TokenAuthentication(String defaultFilterProcessesUrl,SysUserBPOImpl sysUserBPOImpl,SysFunctionBPOImpl sysFunctionBPOImpl,TokenAuthenticationSuccess tokenAuthenticationSuccess ,TokenAuthenticationFailure tokenAuthFailureHandle) {
		super(defaultFilterProcessesUrl);
		super.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(defaultFilterProcessesUrl));
		super.setAuthenticationManager(new AuthenticationManager() {
			@Override
			public Authentication authenticate(Authentication authentication) throws AuthenticationException {
				return authentication;
			}
		});
		// 验证成功
		setAuthenticationSuccessHandler(tokenAuthenticationSuccess);
		// 验证失败
		setAuthenticationFailureHandler(tokenAuthFailureHandle);
		this.sysUserBPO = sysUserBPOImpl;
		this.sysFunctionBPO = sysFunctionBPOImpl;
	}
	
	/**
	  * 对不需要验证的URL放行
	 */
	@Override
	public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;
		// 是否放行匹配结果
		boolean matchResult = false;
		PathMatcher matcher = new AntPathMatcher();
		String requestPath = request.getRequestURI();
		String [] arrPattern =  ScyConstants.AUTH_ALLLOW_URL.split(",");
		if(arrPattern!=null) {
			for(String patternPath:arrPattern) {
				if(matcher.match(patternPath, requestPath)) {
					matchResult = true;
					break;
				}
			}
		}
		// 匹配成功放行
		if (matchResult) {
			chain.doFilter(request, response);
		} else {
			super.doFilter(req, res, chain);
		}
	}
	
	/**
	  * 通过 Token 进行身份验证
	 */
	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
		AbstractAuthenticationToken userAuthenticationToken = null;
		if(
				(request.getHeader(ScyConstants.AUTH_USER_TOKEN)!=null && !"".equals(request.getHeader(ScyConstants.AUTH_USER_TOKEN)))
				||
				request.getParameter(ScyConstants.AUTH_USER_TOKEN)!=null
				)
		{
			String token = request.getHeader(ScyConstants.AUTH_USER_TOKEN);
			if(token==null || "".equals(token)) {
				token = request.getParameter(ScyConstants.AUTH_USER_TOKEN);
			}
			SysUser sysUser = null;
			try {
			    sysUser = sysUserBPO.doGetSysUserByToken(token);
			}
			catch(Exception er) {
				throw new AuthenticationServiceException(WebRetCodeEnum.RET_CODE_0801006.getCode());
			}
			if(sysUser==null) {
				throw new AuthenticationServiceException(WebRetCodeEnum.RET_CODE_0801005.getCode());
			}
			Date tokenCreateTime = UfdmDateUtil.stringToDate(sysUser.getTokenCreateTime(),"yyyy-MM-dd HH:mm:ss");
			int tokenValidMinutes = UfdmDateUtil.getBetweenMinutes(tokenCreateTime,new Date());
			// 判断是否超时
			if(tokenValidMinutes > ScyConstants.TOKEN_VALID_MINUTES) {
				throw new AuthenticationServiceException(WebRetCodeEnum.RET_CODE_0801009.getCode());
			}
			try {
				// 设置用户的权限
				Collection<GrantedAuthority> grantedAuthorities = null;
				grantedAuthorities = sysFunctionBPO.doGetGantedAuthoritiestByUserId(sysUser.getId());
				sysUser.setGrantedAuthorities(grantedAuthorities);
				userAuthenticationToken = new UsernamePasswordAuthenticationToken(sysUser, sysUser.getPassword(),sysUser.getAuthorities());
			}
			catch(Exception er) {
				throw new AuthenticationServiceException(WebRetCodeEnum.RET_CODE_0801010.getCode());
			}
		}
		else {
			throw new AuthenticationServiceException(WebRetCodeEnum.RET_CODE_0801008.getCode());
		}
		return userAuthenticationToken;
	}

}

